#include <stdarg.h>
#include "types.h"
#include "console.h"
#include "print.h"

static char digits[] = "0123456789abcdef";

// 打印整形数据
static void print_int(int xx, int base, int sign)
{
    char buf[16];
    int i;
    unsigned int x;

    if(sign && (sign = xx < 0))
        x = -xx;
    else
        x = xx;

    i = 0;
    do {
        buf[i++] = digits[x % base];
    } while((x /= base) != 0);

    if(sign)
        buf[i++] = '-';

    while(--i >= 0)
        cons_putc(buf[i]);
}

// 打印指针数据
static void print_ptr(u64 x)
{
    int i;
    cons_putc('0');
    cons_putc('x');

    for (i = 0; i < (sizeof(u64) * 2); i++, x <<= 4)
        cons_putc(digits[x >> (sizeof(u64) * 8 - 4)]);
}

// 打印数据.目前支持 %d, %x, %p, %s.
void printk(char *fmt, ...)
{
    va_list ap;
    int i, c;
    char *s;

    if (fmt == 0)
        return;

    va_start(ap, fmt);
    for(i = 0; (c = fmt[i] & 0xff) != 0; i++) {
        if(c != '%'){
            cons_putc(c);
            continue;
        }

        c = fmt[++i] & 0xff;
        if(c == 0)
            break;

        switch(c){
        case 'd':
            print_int(va_arg(ap, int), 10, 1);
            break;

        case 'x':
            print_int(va_arg(ap, int), 16, 1);
            break;

        case 'p':
            print_ptr(va_arg(ap, u64));
            break;

        case 's':
            if((s = va_arg(ap, char*)) == 0)
                s = "(null)";

            for(; *s; s++)
                cons_putc(*s);
            break;

        case '%':
            cons_putc('%');
            break;

        default:
            // Print unknown % sequence to draw attention.
            cons_putc('%');
            cons_putc(c);
            break;
        }
    }
}

void panic(char *s)
{
    printk("panic: ");
    printk(s);
    printk("\n");
    for(;;);
}

void printk_test(void)
{
    int  val = 32;
    int *ptr = (int *)0x1234567812345678;

    pr_test("kernel printk test start.\n");
    pr_test("%%s test: %s\n", "this is string");
    pr_test("%%d test: val = %d\n", val);
    pr_test("%%x test: val = 0x%x\n", val);
    pr_test("%%p test: ptr = %p\n", ptr);
    pr_test("kernel printk test end.\n");
}